using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Input.Touch;


namespace Services
{
    public interface IInputManager
    {
        event InputManager.Tap OnDoubleTap;
        event InputManager.Tap OnTap;
        event InputManager.Tap OnPress;
        event InputManager.Pinch OnPinch;
        event InputManager.Drag OnDrag;
        event InputManager.DragCompleted OnDragCompleted;
        //event InputManager.Drag OnHorizontalDrag;
        //event InputManager.Drag OnVerticalDrag;
    }

    public class InputManager : Microsoft.Xna.Framework.GameComponent, IInputManager
    {
        static readonly float DOUBLE_TAP_INTERVAL = 0.2f;
        static readonly float SINGLE_TAP_INTERVAL = 0.2f;
        static readonly float LONG_TAP_INTERVAL = 0.3f;

        public InputManager(Game game)
            : base(game)
        {
            this.UpdateOrder = (int)ComponentOrders.INPUT;
            game.Services.AddService(typeof(IInputManager), this);
        }

        protected override void Dispose(bool disposing)
        {
            Game.Services.RemoveService(typeof(IInputManager));
            base.Dispose(disposing);
        }

        bool tap_pending = false;
        float time_since_last_release = 10000.0f;
        float time_since_last_press = 10000.0f;
        Vector2 pending_tap_position;

        Matrix screen_transform;
        public override void Initialize()
        {
            screen_transform = Matrix.CreateScale(Game.GraphicsDevice.Viewport.Width / 480.0f, Game.GraphicsDevice.Viewport.Height / 800.0f, 1.0f);
            TouchPanel.EnabledGestures = 
                GestureType.DoubleTap | 
                GestureType.Tap | 
                GestureType.Hold | 
                GestureType.Pinch |
                GestureType.FreeDrag |
              //  GestureType.HorizontalDrag |
                GestureType.DragComplete;

            base.Initialize();
        }

        bool mouse_pressed(MouseState mouse_state)
        {
#if WINDOWS || XBOX
            if (mouse_state.LeftButton == ButtonState.Pressed)
                return true;
#endif
            return false;
        }

        bool mouse_released(MouseState mouse_state)
        {
#if WINDOWS || XBOX
            if (mouse_state.LeftButton == ButtonState.Released)
                return true;
#endif
            return false;
        }

        bool skip_next_frame = false;
        bool dragging = false;
        MouseState prev_mouse_state = new MouseState();
        public override void Update(GameTime gameTime)
        {
            var curr_mouse_state = Mouse.GetState();
            if (curr_mouse_state.LeftButton == ButtonState.Pressed &&
                prev_mouse_state.LeftButton == ButtonState.Released)
            {
                if (OnTap != null)
                    OnTap(new Vector2(curr_mouse_state.X, curr_mouse_state.Y));
            }

            if (curr_mouse_state.RightButton == ButtonState.Pressed &&
                prev_mouse_state.RightButton == ButtonState.Released)
            {
                if (OnDoubleTap != null)
                    OnDoubleTap(new Vector2(curr_mouse_state.X, curr_mouse_state.Y));
            }

            if (Keyboard.GetState().IsKeyDown(Keys.Space))
            {
                if (OnPress != null)
                    OnPress(new Vector2(curr_mouse_state.X, curr_mouse_state.Y));
            }

            //emulazione pinch
            if (curr_mouse_state.RightButton == ButtonState.Pressed && Keyboard.GetState().IsKeyDown(Keys.LeftControl))
            {
                if (OnPinch != null)
                    OnPinch(new Vector2(curr_mouse_state.X, curr_mouse_state.Y), Vector2.Zero, new Vector2(curr_mouse_state.X - prev_mouse_state.X, curr_mouse_state.Y - prev_mouse_state.Y), Vector2.Zero);
            }

            //emulazione drag
            if (curr_mouse_state.LeftButton == ButtonState.Pressed && Keyboard.GetState().IsKeyDown(Keys.LeftControl))
            {
                if(OnDrag != null)
                    OnDrag(new Vector2(curr_mouse_state.X, curr_mouse_state.Y));
                dragging = true;
            }
            //emulazione dragcompleted
            if (curr_mouse_state.LeftButton == ButtonState.Released && dragging)
            {
                dragging = false;
                if (OnDragCompleted != null)
                    OnDragCompleted();
            }
            

            prev_mouse_state = curr_mouse_state;

            while (TouchPanel.IsGestureAvailable)
            {
                GestureSample gs = TouchPanel.ReadGesture();

                switch (gs.GestureType)
                {
                    case GestureType.Tap:
                        if (OnTap != null)
                            OnTap(gs.Position);
                        break;
                    case GestureType.DoubleTap:
                        if (OnDoubleTap != null)
                            OnDoubleTap(gs.Position);
                        break;
                    case GestureType.Hold:
                        if (OnPress != null)
                            OnPress(gs.Position);
                        break;
                    case GestureType.Pinch:
                        if (OnPinch != null)
                            OnPinch(gs.Position, gs.Position2, gs.Delta, gs.Delta2);
                        break;
                    case GestureType.FreeDrag:
                        if (OnDrag != null)
                            OnDrag(gs.Position);
                        break;
                    /*case GestureType.HorizontalDrag:
                        if (OnHorizontalDrag != null)
                            OnHorizontalDrag(gs.Position);
                        break;*/
                    case GestureType.DragComplete:
                        if (OnDragCompleted != null)
                            OnDragCompleted();
                        break;


                }
            }

            /*  
            var dt = (float)gameTime.ElapsedGameTime.TotalSeconds;

            var mouse_state = Mouse.GetState();

            time_since_last_release += dt;
            var touches = TouchPanel.GetState();
      
            bool pressed = mouse_pressed(mouse_state);
            if (mouse_released(mouse_state))
                time_since_last_release = 0.0f;

            for (int i = 0; i < touches.Count; i++)
            {
                if (touches[i].State == TouchLocationState.Released)
                    time_since_last_release = 0.0f;
                pressed = pressed || (touches[i].State != TouchLocationState.Released) || mouse_pressed(mouse_state);
            }


            //if (touches.Any(t => t.State == TouchLocationState.Released) || mouse_released(mouse_state))
            //{
            //    time_since_last_release = 0.0f;
            //}

            time_since_last_press += dt;
            //pressed = touches.Any(t => t.State != TouchLocationState.Released) || mouse_pressed(mouse_state);
            if (pressed && tap_pending == false && skip_next_frame == false)
            {
              time_since_last_press = 0.0f;
              tap_pending = true;
      #if WINDOWS || XBOX
              pending_tap_position = new Vector2(mouse_state.X, mouse_state.Y);
      #else
              pending_tap_position = touches.First(t => t.State != TouchLocationState.Released).Position;
      #endif
            }
            skip_next_frame = false;

            if (pressed && tap_pending && time_since_last_press > LONG_TAP_INTERVAL)
            {
              tap_pending = false;
              skip_next_frame = true;
              //System.Diagnostics.Debug.WriteLine("press");
              if (OnPress != null)
                OnPress(pending_tap_position);
            }
            else if (pressed && tap_pending && time_since_last_release < DOUBLE_TAP_INTERVAL && time_since_last_release < time_since_last_press)
            {
              //System.Diagnostics.Debug.WriteLine("double tap");
              tap_pending = false;
              skip_next_frame = true;
      #if WINDOWS || XBOX
                var p = new Vector2(mouse_state.X, mouse_state.Y);
      #else
              Vector2 p = new Vector2();
              for (int i = 0; i < touches.Count; i++)
              {
                  if (touches[i].State != TouchLocationState.Released)
                  {
                      p = touches[i].Position;
                      break;
                  }
              }
              //var p = touches.First(t => t.State != TouchLocationState.Released).Position;
      #endif
              if (OnDoubleTap != null)
                OnDoubleTap(p);
            }
            else if (pressed == false && tap_pending && time_since_last_press > SINGLE_TAP_INTERVAL)
            {
              //System.Diagnostics.Debug.WriteLine("tap");
              tap_pending = false;
              if (OnTap != null)
                OnTap(pending_tap_position);
            }

            prev_mouse_state = mouse_state;
              */
            base.Update(gameTime);
        }

        public delegate void Tap(Vector2 tap_position);
        public delegate void Pinch(Vector2 position1, Vector2 position2, Vector2 delta1, Vector2 delta2);
        public delegate void Drag(Vector2 position);
        public delegate void DragCompleted();
        public event Tap OnTap;
        public event Tap OnDoubleTap;
        public event Tap OnPress;
        public event Pinch OnPinch;
        public event Drag OnDrag;
        //public event Drag OnHorizontalDrag;
        //public event Drag OnVerticalDrag;
        public event DragCompleted OnDragCompleted;
    }
}
